import { useEffect, useRef, useState, useCallback, useReducer } from "react";
import { Project } from "screen/project-list/list";
import { MjcResponseData } from "service/type";
import { addProject, editProject } from "service/project-list/index";
import { useMutation, useQuery, useQueryClient } from "react-query";
import { message } from "antd";
export const cleanObject = (object: { [key: string]: unknown }) => {
  // Object.assign({}, object)
  const result = { ...object };
  Object.keys(result).forEach((key) => {
    const value = result[key];
    if (isVoid(value)) {
      delete result[key];
    }
  });
  return result;
};
export const isVoid = (value: unknown) =>
  value === undefined || value === null || value === "";
export const isFalsy = (value: any) => (value === 0 ? false : !value);
export const useMount = (callBack: () => void) => {
  useEffect(() => {
    callBack();
    // eslint-disable-next-line react-hooks/exhaustive-deps
    return () => {};
  }, []);
};
export const useDebounce = (value: any, delay?: number) => {
  const [debounceValue, setDebounceValue] = useState(value);
  useEffect(() => {
    const timeout = setTimeout(() => {
      setDebounceValue(value);
    }, delay);
    // eslint-disable-next-line react-hooks/exhaustive-deps
    return () => {
      clearTimeout(timeout);
    };
  }, [value, delay]);
  return debounceValue;
};
interface State<D> {
  error: Error | null;
  data: D | null;
  stat: "idle" | "loading" | "error" | "success";
}
const defaultInitalState: State<null> = {
  stat: "idle",
  data: null,
  error: null,
};
const defaultConfig = {
  thorwOnError: false,
};
const useSafeDispatch = <T>(dispatch: (...args: T[]) => void) => {
  const mountedRef = useMountedRef();
  return useCallback(
    (...args: T[]) => (mountedRef.current ? dispatch(...args) : void 0),
    [dispatch, mountedRef]
  );
};
export const useAsync = <D>(
  initialState?: State<D>,
  initConfig?: typeof defaultConfig
) => {
  const config = { ...defaultConfig, ...initConfig };
  const useAsync = (state: State<D>, action: Partial<State<D>>) => {
    return {
      ...state,
      ...action,
    };
  };
  const [state, dispatch] = useReducer(useAsync, {
    ...defaultInitalState,
    ...initialState,
  });
  // const [state, dispatch] = useReducer((state:State<D>,action:Partial<State<D>>) => {

  // },{
  //   ...defaultInitalState,
  //   ...initialState,
  // };
  const mountedRef = useMountedRef();
  const safeDispatch = useSafeDispatch(dispatch);
  const [retry, setretry] = useState(() => () => {});
  const setData = useCallback(
    (data: D) => {
      safeDispatch({
        data,
        stat: "success",
        error: null,
      });
    },
    [safeDispatch]
  );
  const setError = useCallback(
    (error: Error) => {
      safeDispatch({
        data: null,
        stat: "error",
        error,
      });
    },
    [safeDispatch]
  );
  //触发异步请求
  const run = useCallback(
    (
      promise: Promise<MjcResponseData>,
      runConfig?: {
        retry: () => Promise<MjcResponseData>;
      }
    ) => {
      if (!promise || !promise.then) {
        //不是promise
        return Promise.reject("请传入promise类型");
      }
      setretry(() => () => {
        if (runConfig?.retry) {
          run(runConfig?.retry(), runConfig);
        }
      });
      safeDispatch({ stat: "loading" });
      return promise
        .then((data) => {
          setData(data.data || []);
          return data.data || [];
        })
        .catch((err) => {
          setError(err);
          if (config.thorwOnError) {
            return Promise.reject(err);
          }
          return err;
        });
    },
    [config.thorwOnError, safeDispatch, setData, setError]
  );

  return {
    isIdle: state.stat === "idle",
    isLoading: state.stat === "loading",
    isError: state.stat === "error",
    run,
    setData,
    setError,
    ...state,
    retry,
  };
};
//
export const useDocumentTitle = (
  title: string,
  keepOnUnmounte: boolean = true
) => {
  const oldTitle = useRef(document.title).current;

  useEffect(() => {
    document.title = title;
  }, [title]);
  useEffect(() => {
    return () => {
      if (!keepOnUnmounte) {
        document.title = oldTitle;
      }
    };
  }, [keepOnUnmounte, oldTitle]);
};
export const resetRoute = () => {
  window.location.href = window.location.origin;
};
/**
 * 传入一个对象，和键集合，返回对应的对象中的键值对
 * @param obj
 * @param keys
 */
export const subset = <
  O extends { [key in string]: unknown },
  K extends keyof O
>(
  obj: O,
  keys: K[]
) => {
  const filteredEntries = Object.entries(obj).filter(([key]) =>
    keys.includes(key as K)
  );
  return Object.fromEntries(filteredEntries) as Pick<O, K>;
};
export const useEdiProject = (paramss: Partial<Project>) => {
  const queryClient = useQueryClient();
  const queryKey = ["projects", paramss];
  return useMutation(
    (params: Partial<Project>) => {
      return editProject(params).then((res) => res.data);
    },
    {
      onSuccess: () => queryClient.invalidateQueries(queryKey),
      onError: (error: any, newItem, context: any) => {
        queryClient.setQueryData(queryKey, context.perviousItems);
        if (error.code != 0) {
          message.error(error?.message);
        }
      },
      //mutate一旦被调用，onMutate立刻发生，抛出异常后，在onError中回滚状态
      async onMutate(target) {
        const perviousItems = queryClient.getQueryData(queryKey);
        queryClient.setQueryData(queryKey, (old?: Project[]) => {
          return (
            old?.map((project) => {
              return project.id == target.id
                ? { ...project, ...target }
                : project;
            }) || []
          );
        });
        return { perviousItems };
      },
    }
  );
};
//返回组件的挂载状态，如果还没挂载或者已经卸载，返回false；反之，返回true
export const useMountedRef = () => {
  const mountedRef = useRef(false);
  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
    };
  }, []);

  return mountedRef;
};
export const useAddProject = () => {
  const queryClient = useQueryClient();
  return useMutation(
    (data: Partial<Project>) => {
      return addProject(data);
    },
    {
      onSuccess: () => queryClient.invalidateQueries("projects"),
      onError: (err: any) => {
        if (err.code != 0) {
          message.error(err?.message);
        }
      },
    }
  );
};
